fstats_experimental_design.f90 Source File


Source Code

! SPDX-FileCopyrightText: 2022-2026 Jason Christopherson
! SPDX-License-Identifier: MIT
!
! MIT License
!
! Copyright (c) 2022-2026 Jason Christopherson
!
! Permission is hereby granted, free of charge, to any person obtaining a copy
! of this software and associated documentation files (the "Software"), to deal
! in the Software without restriction, including without limitation the rights
! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! copies of the Software, and to permit persons to whom the Software is
! furnished to do so, subject to the following conditions:
!
! The above copyright notice and this permission notice shall be included in all
! copies or substantial portions of the Software.
!
! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
! SOFTWARE.

module fstats_experimental_design
    !! Shared types for experimental design generation, modeling, and analysis.
    use iso_fortran_env
    use fstats_regression, only : regression_statistics
    implicit none
    private
    
    public :: doe_model
    public :: doe_diagnostics
    public :: doe_prediction
    public :: doe_residuals
    public :: doe_efficiency_metrics
    public :: doe_rsm_model
    public :: doe_optimization_result
    public :: doe_comparison_result
    public :: doe_anova_table

    type doe_model
        !! A model used to represent a design of experiments result.  The model
        !! is of the following form.
        !!
        !! $$ Y = \beta_{0} + \sum_{i=1}^{n} \beta_{i} X_{i} + \sum_{i=1}^{n-1} 
        !! \sum_{j=i+1}^{n} \beta_{ij} X_{i} X_{j} + \sum_{i=1}^{n} \beta_{ii} 
        !! X_{i}^{2} + \sum_{i=1}^{n-2} \sum_{j=i+1}^{n-1} \sum_{k=j+1}^{n} 
        !! \beta_{ijk} X_{i} X_{j} X_{k} + \sum_{i=1}^{n} \sum_{j=1 \\ j \neq i}^{n} 
        !! \beta_{iij} X_{i}^{2} X_{j} + \sum_{i=1}^{n} \beta_{iii} X_{i}^{3} $$
        !!
        !! The cross and squared terms are included for a two-way model, and
        !! the triple terms are added for a three-way model.  Each unique
        !! combination of factors appears exactly once.  For two factors, a
        !! two-way model is
        !! \(Y = \beta_{0} + \beta_{1} X_{1} + \beta_{2} X_{2} + \beta_{12} 
        !! X_{1} X_{2} + \beta_{11} X_{1}^{2} + \beta_{22} X_{2}^{2}\).
        integer(int32) :: nway
            !! The number of interaction levels.
        real(real64), allocatable, dimension(:) :: coefficients
            !! The model coefficients, where N is the number of factors.  The
            !! coefficients are ordered as follows, with each group included
            !! only if the model has a sufficient number of interaction levels.
            !!
            !! 1. The constant term: \(\beta_{0}\) (1 term).
            !! 2. Main effects, \(i = 1 \ldots N\): \(\beta_{1}, \beta_{2}, 
            !!    \ldots, \beta_{N}\) (N terms).  Included for nway >= 1.
            !! 3. Two-way cross terms, \(i < j\) in lexicographic order: 
            !!    \(\beta_{12}, \beta_{13}, \ldots, \beta_{1N}, \beta_{23}, 
            !!    \ldots, \beta_{N-1,N}\) (N(N-1)/2 terms).  Included for 
            !!    nway >= 2.
            !! 4. Squared terms: \(\beta_{11}, \beta_{22}, \ldots, 
            !!    \beta_{NN}\) (N terms).  Included for nway >= 2.
            !! 5. Three-way cross terms, \(i < j < k\) in lexicographic order: 
            !!    \(\beta_{123}, \beta_{124}, \ldots, \beta_{N-2,N-1,N}\) 
            !!    (N(N-1)(N-2)/6 terms).  Included for nway >= 3.
            !! 6. Squared-by-linear terms \(X_{i}^{2} X_{j}\), \(i \neq j\), 
            !!    with i as the outer index and j as the inner index: 
            !!    \(\beta_{112}, \beta_{113}, \ldots, \beta_{11N}, 
            !!    \beta_{221}, \beta_{223}, \ldots, \beta_{NN,N-1}\) 
            !!    (N(N-1) terms).  Included for nway >= 3.
            !! 7. Cubed terms: \(\beta_{111}, \beta_{222}, \ldots, 
            !!    \beta_{NNN}\) (N terms).  Included for nway >= 3.
            !!
            !! For example, with N = 2 and nway = 2, the order is 
            !! \(\beta_{0}, \beta_{1}, \beta_{2}, \beta_{12}, \beta_{11}, 
            !! \beta_{22}\).
        type(regression_statistics), allocatable, dimension(:) :: stats
            !! Statistical information for each model parameter.
        logical, allocatable, dimension(:) :: map
            !! An array denoting if a model coefficient should be included
            !! as part of the model (true), or neglected (false).
        real(real64), allocatable, dimension(:,:) :: covariance
            !! The unscaled parameter covariance matrix 
            !! \( \left( X^{T} X \right)^{-1} \), where \( X \) is the design
            !! matrix used to fit the model.  Only the parameters included in 
            !! the model (map = true) are represented, in coefficient order.  
            !! This is populated by doe_fit_model, and is used to compute 
            !! prediction intervals.
        real(real64) :: mse = 0.0d0
            !! The residual mean squared error of the fit, \( SS_{res} / 
            !! (m - p) \).  This is only meaningful if dof > 0.
        integer(int32) :: dof = 0
            !! The residual degrees of freedom of the fit, \( m - p \).  A 
            !! value of zero indicates the fit information is not available
            !! (e.g. the model was not created by doe_fit_model).
    end type

    type doe_diagnostics
        !! Model diagnostics and goodness-of-fit metrics.
        real(real64) :: r_squared
            !! The coefficient of determination (R²), range [0, 1].
        real(real64) :: r_squared_adjusted
            !! The adjusted R² accounting for model complexity.
        real(real64) :: rmse
            !! Root mean square error.
        real(real64) :: residual_std_error
            !! Residual standard error (standard deviation of residuals).
        real(real64) :: f_statistic
            !! Overall F-statistic for the model.
        real(real64) :: f_p_value
            !! P-value for the overall F-statistic.
        real(real64) :: mean_response
            !! Mean of the response variable.
        integer(int32) :: n_observations
            !! Number of observations.
        integer(int32) :: n_parameters
            !! Number of model parameters (including intercept).
    end type

    type doe_prediction
        !! Prediction with uncertainty quantification.
        real(real64), allocatable, dimension(:) :: predicted_values
            !! Predicted response values.
        real(real64), allocatable, dimension(:) :: confidence_lower
            !! Lower confidence interval bounds.
        real(real64), allocatable, dimension(:) :: confidence_upper
            !! Upper confidence interval bounds.
        real(real64), allocatable, dimension(:) :: prediction_lower
            !! Lower prediction interval bounds.
        real(real64), allocatable, dimension(:) :: prediction_upper
            !! Upper prediction interval bounds.
        real(real64) :: confidence_level
            !! Confidence level (e.g., 0.95 for 95% CI).
    end type

    type doe_residuals
        !! Residual analysis data.
        real(real64), allocatable, dimension(:) :: residuals
            !! Raw residuals: y - y_predicted.
        real(real64), allocatable, dimension(:) :: standardized_residuals
            !! Standardized residuals for outlier detection.
        real(real64), allocatable, dimension(:) :: predicted_values
            !! Predicted response values.
        real(real64), allocatable, dimension(:) :: observed_values
            !! Observed response values.
        real(real64) :: residual_mean
            !! Mean of residuals (should be ~0).
        real(real64) :: residual_std
            !! Standard deviation of residuals.
    end type

    type doe_efficiency_metrics
        !! Design efficiency metrics for evaluating design quality.
        real(real64) :: d_efficiency
            !! D-efficiency: \((|X'X|^(1/p))^(1/n)\) where p=params, n=runs.
            !! Range [0,1]. Higher is better (max=1 for orthogonal designs).
        real(real64) :: a_efficiency
            !! A-efficiency: \(p / trace((X'X)^-1)\). Range [0,1]. 
            !! Higher is better.
        real(real64) :: g_efficiency
            !! G-efficiency: 1 - (max_prediction_variance / avg_prediction_variance)
        real(real64) :: orthogonality
            !! Orthogonality measure: \(1.0\) if perfectly orthogonal, \(<1.0\) 
            !! otherwise.
        logical :: is_orthogonal
            !! True if design is perfectly orthogonal.
        integer(int32) :: n_runs
            !! Number of design runs.
        integer(int32) :: n_factors
            !! Number of factors.
        integer(int32) :: n_parameters
            !! Number of model parameters.
    end type

    type doe_rsm_model
        !! Response Surface Model (quadratic model for RSM).
        type(doe_model) :: base_model
            !! Base fitted model.
        real(real64), allocatable, dimension(:) :: linear_coeff
            !! Linear coefficients for each factor.
        real(real64), allocatable, dimension(:) :: quadratic_coeff
            !! Quadratic coefficients (main effects squared).
        real(real64), allocatable, dimension(:) :: interaction_coeff
            !! Interaction coefficients.
        real(real64) :: intercept
            !! Model intercept.
        real(real64) :: response_at_center
            !! Predicted response at design center (coded 0,0,...,0).
        integer(int32) :: n_factors
            !! Number of factors.
    end type

    type doe_optimization_result
        !! Results from RSM-based optimization.
        real(real64), allocatable, dimension(:) :: optimal_coded_factors
            !! Optimal factor settings (in coded scale).
        real(real64), allocatable, dimension(:) :: optimal_natural_factors
            !! Optimal factor settings (in natural scale).
        real(real64) :: optimal_response
            !! Predicted response at optimal point.
        integer(int32) :: iteration_count
            !! Number of iterations to converge.
        logical :: converged
            !! Whether optimization converged.
        character(len=256) :: method
            !! Optimization method used.
        real(real64) :: convergence_tolerance
            !! Tolerance used for convergence.
    end type

    type doe_comparison_result
        !! Results from comparing two models.
        real(real64) :: f_statistic
            !! F-statistic for model comparison.
        real(real64) :: p_value
            !! P-value for the F-test.
        real(real64) :: rss_full
            !! Residual sum of squares for full model.
        real(real64) :: rss_reduced
            !! Residual sum of squares for reduced model.
        integer(int32) :: df_full
            !! Degrees of freedom for full model.
        integer(int32) :: df_reduced
            !! Degrees of freedom for reduced model.
        integer(int32) :: df_diff
            !! Difference in degrees of freedom.
        logical :: significant_difference
            !! True if models differ significantly (p < 0.05).
        character(len=256) :: conclusion
            !! Interpretation of comparison results.
    end type

    type doe_anova_table
        !! ANOVA table for overall model fit assessment.
        real(real64) :: ss_total
            !! Total sum of squares.
        real(real64) :: ss_model
            !! Model sum of squares.
        real(real64) :: ss_residual
            !! Residual sum of squares.
        integer(int32) :: df_total
            !! Total degrees of freedom.
        integer(int32) :: df_model
            !! Model degrees of freedom.
        integer(int32) :: df_residual
            !! Residual degrees of freedom.
        real(real64) :: ms_model
            !! Model mean square.
        real(real64) :: ms_residual
            !! Residual mean square.
        real(real64) :: f_statistic
            !! F-statistic.
        real(real64) :: p_value
            !! P-value for the F-test.
        real(real64) :: r_squared
            !! R-squared value.
    end type
end module fstats_experimental_design